#include "NcVarWrapper.h"
#include "NcWrapper.h"
#include "OCMain/OCMath.h"

namespace OCPP {
	using namespace Volume;

	NcVarWrapper::NcVarWrapper(NcVar var, NetcdfFileReaderPtr ptr)
		:_var(var)
		,_ncWrapperPtr(ptr)
	{
		auto attrs = var.getAtts();
		for (auto [name, attr] : attrs)
		{
			if (name == "units")
			{
				attr.getValues(_ncGridData._unit);
			}
			else if (name == "_FillValue")
			{
				float value;
				attr.getValues(&value);
				if(!Math::isNaN(value))
					_ncGridData._fillValue = value;
			}
			else if (name == "missing_value")
			{
				float value;
				attr.getValues(&value);
				if (!Math::isNaN(value))
					_ncGridData._missingValue = value;
			}
		}
	}

	String NcVarWrapper::getTimeString(int index)
	{
		const auto& unitAttr = _var.getAtt("units");
		if (!unitAttr.isNull())
		{
			String units;
			try {
				unitAttr.getValues(units);
			}
			catch (...) {}
		}

		return "";
	}

	FloatVector NcVarWrapper::readFloat()
	{
		return NcUtil::readFloat(_var);
	}

	const NcDimWrapperList& NcVarWrapper::getDimList()
	{
		return _ncDimList;
	}

	void NcVarWrapper::addDimVar(std::shared_ptr<NcDimWrapper> dim,bool splitDimZ,bool mustBeZ, const VolumeOptions& options)
	{
		auto& _volumeExtent = _ncGridData.getExtent();
		String name = dim->getName();
		if (NcUtil::isDimT(name, options))
		{
			hasDimTime = true;
			_ncDimList.push_back(dim);
			_shape.push_back(1);
		}
		else if (NcUtil::isDimZ(name, options) || mustBeZ)
		{
			const FloatVector& fv = dim->getFloatVec();
			size_t size = fv.size();
			assert(size != 0);

			_volumeExtent.zMin = fv[0];
			_volumeExtent.zMax = fv[fv.size() - 1];

			if (splitDimZ)
			{
				_ncDimList.push_back(dim);
				_volumeExtent.dimZ = 1;
			}
			else
			{
				_volumeExtent.dimZ = (int)fv.size();
			}

			_shape.push_back(size);
		}
		else if (NcUtil::isDimY(name, options))
		{
			const FloatVector& fv = dim->getFloatVec();
			size_t size = fv.size();
			assert(size != 0);
			_volumeExtent.yMin = fv[0];
			_volumeExtent.yMax = fv[size - 1];
			_volumeExtent.dimY = (int)size;
			_shape.push_back(size);
		}
		else if (NcUtil::isDimX(name, options))
		{
			const FloatVector& fv = dim->getFloatVec();
			size_t size = fv.size();
			assert(size != 0);
			_volumeExtent.xMin = fv[0];
			_volumeExtent.xMax = fv[size - 1];
			_volumeExtent.dimX = (int)size;
			_shape.push_back(size);
		}
		else
		{
			const FloatVector& fv = dim->getFloatVec();
			size_t size = fv.size();
			assert(size != 0);
			_shape.push_back(size);
		}
	}

	StringVector NcVarWrapper::getDims()
	{
		StringVector sv;
		const auto& dimensions = _var.getDims();
		for (auto i = 0; i < dimensions.size(); i++)
		{
			const auto& dimension = dimensions.at(i);
			auto name = dimension.getName();
			sv.push_back(name);
		}
		return sv;
	}

	String NcVarWrapper::getUnitsString()
	{
		return "";
	}

	GridShape NcVarWrapper::getShape()
	{
		GridShape shape;
		const auto& dims = _var.getDims();
		for (const auto& dim : dims)
		{
			shape.push_back(dim.getSize());
		}
		return shape;
	}

	String NcVarWrapper::getName()
	{
		return _var.getName();
	}
}


